package com.dwj.auto.comment.common.utils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.dwj.auto.comment.common.annotation.Condition;
import com.dwj.auto.comment.common.annotation.Order;
import com.dwj.auto.comment.common.enums.OrderType;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @ClassName Pagination
 * @Description 分页抽象类
 * @Author dwjian
 * @Date 2020/1/13 0:18
 */
@Data
@Slf4j
public abstract class Pagination<T,R> implements IPage<T> {
    private List<R> data;
    private long page = 1L;
    private long limit = 15L;
    private long count;

    @Condition
    private Integer isDel = 0;
    private QueryWrapper<T> wrapper;

    public Pagination(){
    }

    public Pagination(long page, long limit){
        this.data = Collections.emptyList();
        this.page = page;
        this.limit = limit;
        this.count = 0L;
    }

    protected abstract Class<R> getRespClass();

    private QueryWrapper<T> intWrapper(){
        QueryWrapper<T> wrapper = new QueryWrapper<>();
        Field[] fields = this.getClass().getDeclaredFields();
        if(fields != null){
            for (Field field : fields) {
                Condition condition = field.getAnnotation(Condition.class);
                if(condition != null){
                    field.setAccessible(true);
                    Object value = null;
                    try {
                        value = field.get(this);
                    } catch (IllegalAccessException e) {
                        log.warn("reflection anomaly!");
                    }
                    if(!StringUtils.isEmpty(value)){
                        switch (condition.type()){
                            case EQ:
                                wrapper.eq(ConvertUtil.humpToLine2(field.getName()), value);
                                break;
                            case LIKE:
                                wrapper.like(ConvertUtil.humpToLine2(field.getName()), value);
                        }
                    }
                }
                Order order = field.getAnnotation(Order.class);
                if(order != null){
                    if(!StringUtils.isEmpty(order.order())){
                        switch (order.order()){
                            case DESC:
                                wrapper.orderByDesc(ConvertUtil.humpToLine2(field.getName()));
                                break;
                            case ASC:
                                wrapper.orderByAsc(ConvertUtil.humpToLine2(field.getName()));
                        }
                    }
                }
            }
        }
        return wrapper;
    }

    public QueryWrapper<T> getWrapper() {
        return intWrapper();
    }

    @Override
    public List<OrderItem> orders() {
        return Collections.emptyList();
    }

    @Override
    public List<T> getRecords() {
        return Collections.emptyList();
    }

    @Override
    public IPage<T> setRecords(List<T> records) {
        List<R> resultList = new ArrayList<>();
        try {
            for (T record : records) {
                R instance = getRespClass().newInstance();
                BeanUtils.copyProperties(record, instance, instance.getClass());
                resultList.add(instance);
            }
        } catch (InstantiationException e) {
            log.warn("InstantiationException",e);
        } catch (IllegalAccessException e) {
            log.warn("IllegalAccessException",e);
        }
        this.setData(resultList);
        return this;
    }

    @Override
    public long getTotal() {
        return this.count;
    }

    @Override
    public IPage<T> setTotal(long total) {
        this.count = total;
        return this;
    }

    @Override
    public long getSize() {
        return this.limit;
    }

    @Override
    public IPage<T> setSize(long size) {
        this.limit = size;
        return this;
    }

    @Override
    public long getCurrent() {
        return this.page;
    }

    @Override
    public IPage<T> setCurrent(long current) {
        this.page = current;
        return this;
    }
}
